﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using grafo;

namespace CamminiHamiltoniani {
    public partial class Form1 : Form {
        private Grafo _myGrafo;
        private List<uint[]> _listaCfc;
        private uint[] _current;
        private List<string> _listanodi;
        private List<string[]> _listarchi;
        private FileStream _fs1;
        private FileStream _fs2;
        private FileStream _fsComp;

        private readonly List<object[]> _mapping = new List<object[]>(); //object[0]=uint object[1]=string

        private string GetNome(uint indice) {
            foreach (var m in _mapping.Where(m => (uint) m[0] == indice))
                return (string) m[1];
            throw new ArgumentException(@"Elemento non presente");
        }

        private uint GetId(string result) {
            foreach (var m in _mapping.Where(m => (string) m[1] == result))
                return (uint) (m[0]);
            throw new ArgumentException(@"Elemento non presente");
        }

        public Form1() {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e) {
            label1.Text = "";
            label2.Text = "";
            splitContainer1.SplitterDistance = 0;

            if (button1.Text == @"Rimuovi cappi") {
                _myGrafo.RimuoviCappi();
                GrafoSuFile(_myGrafo);
                StampaGrafo();
                button1.Text = @"Cerca cfc";
                return;
            }
            _listaCfc = _myGrafo.CFC();
            var flag = true;
            try {
                flag = _myGrafo.SelectCfc(_listaCfc, out _current);

            }
            catch (Grafo.CattivaCfcException ee) {
                GrafoSuFileCfcFail(_myGrafo, ee.Cfc);
                toolStripStatusLabel1.Text = ee.Message;
                button1.Enabled = false;
                StampaGrafo();
                return;
            }
           
            if (flag) {
                if (button1.Text == @"Cerca cfc") {
                    GrafoSuFileCFC(_myGrafo, _current);
                    StampaGrafo();
                    button1.Text = @"Rimuovi cfc";

                    return;
                }
                if (button1.Text == @"Rimuovi cfc")
                {
                    GrafoSuFileCFC(_myGrafo, _current);
                    splitContainer1.SplitterDistance = splitContainer1.Size.Width/2 ;
                    label1.Text = @"Si stanno eliminando i nodi in verde";
                    label2.Text = @"Grafo dopo";
                    StampaGrafoComp();  //per comparare i 2 grafi
                    _myGrafo.RemoveCfc(ref _listaCfc, _current);
                    GrafoSuFile(_myGrafo);
                    StampaGrafo();
                    button1.Text = @"Cerca cfc";
                    return;
                }
            }
            else
            {
                button1.Enabled = false;
                //if(isFormaBase)
                toolStripStatusLabel2.Text = @"Esiste il cammino";
            }
        }

        private void StampaGrafoComp()
        {
            if (_fsComp != null)
                _fsComp.Close();
            var startInfo = new ProcessStartInfo(@".\bin\dot.exe")
            {
                WindowStyle = ProcessWindowStyle.Minimized,
                CreateNoWindow = true,
                Arguments = "-Tgif G.txt -o Gcomp.gif"
            };
            try
            {
                using (var exeProcess = Process.Start(startInfo))
                    exeProcess.WaitForExit();
            }
            catch
            {
                toolStripStatusLabel1.Text = @"Non sono riuscito a creare l'immagine del grafo";
                return;
            }
            _fsComp = new FileStream("GComp.gif", FileMode.Open, FileAccess.Read);
            pictureBox4.Image = Image.FromStream(_fsComp);
        }
        
        private void GrafoSuFileCfcFail(Grafo test, uint[] current) {
            TextWriter tw = new StreamWriter("G.txt");
            tw.WriteLine("graph G {");
            for (uint i = 0; i < test.Dim; i++) {
                for (uint j = 0; j < test.Dim; j++) {
                    if (!test.Matrice[i, j])
                        continue;
                    if (Contains(current, i) && Contains(current, j))
                        tw.WriteLine("{0} -- {1} [color=\"red\" style=bold] ;", GetNome(i), GetNome(j));
                    else
                        tw.WriteLine("{0} -- {1};", GetNome(i), GetNome(j));
                }
            }
            tw.WriteLine("}");
            tw.Close();
            tw.Dispose();
        }

        private void GrafoSuFileCFC(Grafo test, uint[] current) {
            TextWriter tw = new StreamWriter("G.txt");
            tw.WriteLine("graph G {");
            for (uint i = 0; i < test.Dim; i++) {
                for (uint j = 0; j < test.Dim; j++) {
                    if (!test.Matrice[i, j])
                        continue;
                    if (Contains(current, i) && Contains(current, j))
                        tw.WriteLine("{0} -- {1} [color=\"green\" style=bold] ;", GetNome(i), GetNome(j));
                    else {
                        if (Contains(current, i) || Contains(current, j))
                            tw.WriteLine("{0} -- {1} [color=\"blue\" style=bold] ;", GetNome(i), GetNome(j));
                        else
                            tw.WriteLine("{0} -- {1};", GetNome(i), GetNome(j));
                    }
                }
            }
            tw.WriteLine("}");
            tw.Close();
            tw.Dispose();
        }

        private static bool Contains(IEnumerable<uint> dv, uint cs) {
            return dv.Any(u => u == cs);
        }

        private void StampaGrafo() {
            if (_fs1 != null)
                _fs1.Close();
            var startInfo = new ProcessStartInfo(@".\bin\dot.exe") {
                                                                       WindowStyle = ProcessWindowStyle.Minimized,
                                                                       CreateNoWindow = true,
                                                                       Arguments = "-Tgif G.txt -o Gs.gif"
                                                                   };
            try {
                using (var exeProcess = Process.Start(startInfo))
                    exeProcess.WaitForExit();
            }
            catch {
                toolStripStatusLabel1.Text = @"Non sono riuscito a creare l'immagine del grafo";
                return;
            }
            _fs1 = new FileStream("Gs.gif", FileMode.Open, FileAccess.Read);
            pictureBox1.Image = Image.FromStream(_fs1);
            //var myImage = Image.FromFile("G.gif");
            //DisposeImgp(ictureBox1);

            //pictureBox1.Image = myImage;
        }

        private void AnteprimaGrafo() { //quando si crea/carica un nuovo grafo si fanno casini
            if (_fs2 != null)
                _fs2.Close();
            var startInfo = new ProcessStartInfo(@".\bin\dot.exe") {
                                                                       WindowStyle = ProcessWindowStyle.Minimized,
                                                                       CreateNoWindow = true,
                                                                       Arguments = "-Tgif G.txt -o Ga.gif"
                                                                   };
            try {
                using (var exeProcess = Process.Start(startInfo))
                    exeProcess.WaitForExit();
            }
            catch {
                toolStripStatusLabel1.Text = @"Non sono riuscito a creare l'immagine del grafo";
                return;
            }

            _fs2 = new FileStream("Ga.gif", FileMode.Open, FileAccess.Read);
            pictureBox2.Image = Image.FromStream(_fs2);
        }

        private void GrafoSuFile(Grafo test) {
            TextWriter tw = new StreamWriter("G.txt");
            tw.WriteLine("graph G {");
            for (var i = 0; i < test.Dim; i++) {
                for (var j = 0; j < test.Dim; j++) {
                    if (test.Matrice[i, j])
                        tw.WriteLine("{0} -- {1};", GetNome((uint) i), GetNome((uint) j));
                }
            }
            tw.WriteLine("}");
            tw.Close();
        }

        private uint CreaGrafo(out bool[,] m) {
            _listanodi = new List<string>();
            foreach (var b in _listarchi) {
                if (!_listanodi.Contains(b[0]))
                    _listanodi.Add(b[0]);
                if (!_listanodi.Contains(b[1]))
                    _listanodi.Add(b[1]);
            }
            for (uint i = 0; i < _listanodi.Count; i++) {
                var temp = new object[2];
                temp[0] = i;
                temp[1] = _listanodi[(int) i];
                _mapping.Add(temp);
            }

            var dim = (uint) _listanodi.Count;
            m = new bool[dim,dim];
            for (var i = 0; i < dim; i++) { //teoricamente è inutile... ma poi
                for (var j = 0; j < dim; j++)
                    m[i, j] = false;
            }
            foreach (var arc in _listarchi)
                m[GetId(arc[0]), GetId(arc[1])] = true;

            /* m[0, 1] = true;
            m[1, 0] = true;
            m[1, 2] = true;
            m[0, 3] = true;
            m[2, 4] = true;
            m[3, 5] = true;
            m[4, 5] = true;
            //cappi
            m[3, 3] = true;
            m[1, 1] = true;*/
            return dim;
        }

        private void button2_Click(object sender, EventArgs e) {
            DisposeImg(pictureBox2);
            var myImage = Image.FromFile("loading.gif");
            pictureBox2.Image = myImage;
            _listarchi = new List<string[]>();
            for (var i = 0; i < dataGridView2.Rows.Count - 1; i++) {
                var temp = new string[2];
                if (dataGridView2.Rows[i].Cells[0].Value == null ||
                    dataGridView2.Rows[i].Cells[1].Value == null) {
                    toolStripStatusLabel1.Text = @"Arco nella riga " + (i + 1) + @" ignorato in quanto non valido";
                    return;
                }
                temp[0] = dataGridView2.Rows[i].Cells[0].Value.ToString();
                temp[1] = dataGridView2.Rows[i].Cells[1].Value.ToString();
                if (!Contiene(temp))
                    _listarchi.Add(temp);
                else
                    toolStripStatusLabel1.Text = @"Arco nella riga " + (i + 1) + @" ignorato in quanto doppio";
            }
            TextWriter tw = new StreamWriter("G.txt");
            tw.WriteLine("graph G {");
            foreach (var uintse in _listarchi)
                tw.WriteLine("{0} -- {1};", uintse[0], uintse[1]);
            tw.WriteLine("}");
            tw.Close();
            AnteprimaGrafo();
            bool[,] m;
            var dim = CreaGrafo(out m);
            _myGrafo = new Grafo(m, dim);
            GrafoSuFile(_myGrafo);
            pictureBox1.Image = pictureBox2.Image;
            button1.Text = @"Rimuovi cappi";
            splitContainer1.SplitterDistance = 0;
        }

        private bool Contiene(IList<string> temp) {
            return _listarchi.Any(s => s[0] == temp[0] && s[1] == temp[1]);
        }
       
        private static void DisposeImg(PictureBox picture) {
            if (picture.Image == null)
                return;
            var previousImage = picture.Image;
            if (previousImage != Image.FromFile("loading.gif"))
                previousImage.Dispose();
        }

        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) {
            button1.Enabled = true;
            toolStripStatusLabel1.Text = "";
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            /*if(pictureBox4.Visible)
            {
                pictureBox4.Location = new Point(groupBox2.Location.X+5,pictureBox4.Location.Y);
                pictureBox4.Size = new Size((groupBox2.Size.Width-10)/2,pictureBox4.Size.Height);
                pictureBox1.Size = new Size((groupBox2.Size.Width-15)/2,pictureBox1.Size.Height);
                return;
            }
            pictureBox1.Location = new Point(groupBox2.Location.X + 5, pictureBox1.Location.Y);
            pictureBox1.Size = new Size((groupBox2.Size.Width - 20), pictureBox1.Size.Height);*/
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            splitContainer1.SplitterDistance = 0;
        }
        
        private void button3_Click_1(object sender, EventArgs e)
        {
            dataGridView2.RowCount = 1;
            dataGridView2.Rows.Clear();
            pictureBox2.Image = null;
        }

        private void apriToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            dataGridView2.RowCount = 1;
            dataGridView2.Rows.Clear();
            pictureBox2.Image = null;
            var openFileDialog = new OpenFileDialog
            {
                InitialDirectory = Application.StartupPath,
                Filter = @"txt files (*.txt)|*.txt",
                FilterIndex = 1,
                RestoreDirectory = true
            };
            var result = openFileDialog.ShowDialog();

            _listarchi = new List<string[]>();
            if (result != DialogResult.OK)
                return;
            var file = openFileDialog.FileName;
            try
            {
                var flag = true;
                foreach (var line in File.ReadLines(file))
                {
                    if (flag)
                    {
                        flag = false;
                        continue;
                    }
                    var temp = new string[1];
                    temp[0] = " -- ";
                    var posiz = line.IndexOf(';');
                    var line2 = line;
                    if (posiz > 0)
                        line2 = line2.Remove(posiz, 1);
                    var res = line2.Split(temp, StringSplitOptions.None);
                    if (res.Length == 2)
                        _listarchi.Add(res);
                }
            }
            catch (IOException)
            {
                return;
            }
            TextWriter tw = new StreamWriter("G.txt");
            tw.WriteLine("graph G {");
            foreach (var uintse in _listarchi)
                tw.WriteLine("{0} -- {1};", uintse[0], uintse[1]);
            tw.WriteLine("}");
            tw.Close();
            AnteprimaGrafo();
            bool[,] m;
            var dim = CreaGrafo(out m);
            _myGrafo = new Grafo(m, dim);
            GrafoSuFile(_myGrafo);
            pictureBox1.Image = pictureBox2.Image;
            button1.Text = @"Rimuovi cappi";
            foreach (var l in _listarchi)
                dataGridView2.Rows.Add(l);
            splitContainer1.SplitterDistance = 0;
        }

        private void salvaTxtToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            if (_myGrafo == null) return;
            if (tabControl1.SelectedIndex == 1)
            {
                var saveFileDialog1 = new SaveFileDialog
                {
                    InitialDirectory = Application.StartupPath,
                    Filter = @"txt files (*.txt)|*.txt",
                    Title = @"Save an Txt File"
                };
                saveFileDialog1.ShowDialog();

                if (saveFileDialog1.FileName != "")
                {
                    var fileStream = saveFileDialog1.OpenFile();
                    var tw = new StreamWriter(fileStream);

                    tw.WriteLine("graph G {");
                    for (var i = 0; i < _myGrafo.Dim; i++)
                    {
                        for (var j = 0; j < _myGrafo.Dim; j++)
                        {
                            if (_myGrafo.Matrice[i, j])
                                tw.WriteLine("{0} -- {1};", GetNome((uint)i), GetNome((uint)j));
                        }
                    }
                    tw.WriteLine("}");
                    tw.Close();
                }
                toolStripStatusLabel1.Text = @"Devi inserire un nome";
            }
            else
            {
                var saveFileDialog1 = new SaveFileDialog
                {
                    InitialDirectory = Application.StartupPath,
                    Filter = @"txt files (*.txt)|*.txt",
                    Title = @"Save an Txt File"
                };
                saveFileDialog1.ShowDialog();

                if (saveFileDialog1.FileName != "")
                {
                    var fileStream = saveFileDialog1.OpenFile();
                    var tw = new StreamWriter(fileStream);

                    tw.WriteLine("graph G {");
                    for (var i = 0; i < _myGrafo.Dim; i++)
                    {
                        for (var j = 0; j < _myGrafo.Dim; j++)
                        {
                            if (_myGrafo.Matrice[i, j])
                                tw.WriteLine("{0} -- {1};", GetNome((uint)i), GetNome((uint)j));
                        }
                    }
                    tw.WriteLine("}");
                    tw.Close();
                }

            }
        }

        private void salvaImmagineToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            if (pictureBox2.Image == null) return;
            if (tabControl1.SelectedIndex == 1)
            {
                var saveFileDialog1 = new SaveFileDialog
                {
                    InitialDirectory = Application.StartupPath,
                    Filter = @"JPeg Image|*.jpg|Bitmap Image|*.bmp|Gif Image|*.gif",
                    Title = @"Save an Image File"
                };
                saveFileDialog1.ShowDialog();

                if (saveFileDialog1.FileName == "")
                    return;
                var fs = (FileStream)saveFileDialog1.OpenFile();
                switch (saveFileDialog1.FilterIndex)
                {
                    case 1:
                        pictureBox2.Image.Save(fs, System.Drawing.Imaging.ImageFormat.Jpeg);
                        break;
                    case 2:
                        pictureBox2.Image.Save(fs, System.Drawing.Imaging.ImageFormat.Bmp);
                        break;
                    case 3:
                        pictureBox2.Image.Save(fs, System.Drawing.Imaging.ImageFormat.Gif);
                        break;
                }
                fs.Close();
            }
            else
            {
                var saveFileDialog1 = new SaveFileDialog
                {
                    InitialDirectory = Application.StartupPath,
                    Filter = @"JPeg Image|*.jpg|Bitmap Image|*.bmp|Gif Image|*.gif",
                    Title = @"Save an Image File"
                };
                saveFileDialog1.ShowDialog();

                if (saveFileDialog1.FileName == "")
                    return;
                var fs = (FileStream)saveFileDialog1.OpenFile();
                switch (saveFileDialog1.FilterIndex)
                {
                    case 1:
                        pictureBox1.Image.Save(fs, System.Drawing.Imaging.ImageFormat.Jpeg);
                        break;
                    case 2:
                        pictureBox1.Image.Save(fs, System.Drawing.Imaging.ImageFormat.Bmp);
                        break;
                    case 3:
                        pictureBox1.Image.Save(fs, System.Drawing.Imaging.ImageFormat.Gif);
                        break;
                }
                fs.Close();
            }
        }

        private void esciToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }
    }
}